package org.chispa.api.util;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ExpressionLanguage {
	
	public static final String PLAIN_HASH="hash_";
	public static final String PLAIN_ENC="enc_";
	public static final String LIKE="LIKE";
	public static final String NOT_LIKE="NOT LIKE";
	public static final String AND="&&";
	public static final String OR="||";
	public static final String QUOTE="\"";
	public static final String COMMA=",";
	public static final String PROC_HASH="index_";
	public static final String PROC_ENC="dec_";
	public static final String SEC_PAR="secure_";

	public static final String STRING_NAME="str";
	public static final String FLOAT_NAME="float";
	public static final String INTEGER_NAME="int";
	
	public static final String PREFIX_REGEX="PREFIX\\s+\\S+:\\s+\\S+";
	
	public static final String TRIPLE_REGEX="\\S+\\s+\\S+:\\S+\\s+($|\\?)\\S+";
	
	public static final String SECURE_PREFIX=SEC_PAR+"("+FLOAT_NAME+"|"+INTEGER_NAME+"|"+STRING_NAME+"):";
	
	public static final String SECURE_REGEX=SECURE_PREFIX+"\\s*($|\\?)\\S+";
		
	private static Pattern method=Pattern.compile(PLAIN_HASH+"("
			+FLOAT_NAME+"|"+INTEGER_NAME+"|"
			+STRING_NAME+")"
			, Pattern.CASE_INSENSITIVE);
	
	private static Pattern index=Pattern.compile(PROC_HASH+"("
			+FLOAT_NAME+"|"+INTEGER_NAME+"|"
			+STRING_NAME+")"
			, Pattern.CASE_INSENSITIVE);
	
	private static Pattern method_enc=Pattern.compile(PLAIN_ENC+"("
			+FLOAT_NAME+"|"+INTEGER_NAME+"|"
			+STRING_NAME+")"
			, Pattern.CASE_INSENSITIVE);
	
	private static Pattern method_dec=Pattern.compile(PROC_ENC+"("
			+FLOAT_NAME+"|"+INTEGER_NAME+"|"
			+STRING_NAME+")"
			, Pattern.CASE_INSENSITIVE);
	
	//EPIC regular expression!!!!
	public static final String LITERAL_REGEX="([^(\\\\)]\\\")((?<=\\\\)\\\"|[^\\\"])*(?<!\\\\)\\\"";

	private ExpressionLanguage(){};
	
	public static enum Type{
		FLOAT(FLOAT_NAME),INTEGER(INTEGER_NAME),STRING(STRING_NAME);
		
		private String name;

		private Type(String name)
		{
			this.name=name;
		}
		
		public String getName(){return name;}
	}
	
	public static String escapeFromJava(String what)
	{
		return what.replace("\\\"", "\"");
	}
	
	
	public static Type getType(String what)
	{
		what=what.replace(PLAIN_HASH, "").replace(PLAIN_ENC, "");
		for(Type type:Type.values())
		{
			if(type.getName().equalsIgnoreCase(what))
				return type;
		}
		return null;
	}
	
	public static boolean isUnclosedLiteral(String text)
	{
		int count=0;
		for(int i=0;i<text.length();i++)
		{
			char curr=text.charAt(i);
			if(curr=='\"')
			{
				if(!isEscaped(text,i))
					count+=1;
			}
		}
		return (count%2==1);
	}
	
	private static boolean isEscaped(String text,int index)
	{
		char bslash='\\';
		if(index==0)
			return false;
		if(text.charAt(index-1)==bslash)
		{
			if(index==1 || text.charAt(index-2)!=bslash)
				return true;
		}
		return false;
	
	}
	
	public static boolean isObject(String what)
	{
		return what.matches("\\S+:\\S+");
	}
	
	public static boolean matchesHash(String what)
	{
		Matcher methodMatch=method.matcher(what);
		return methodMatch.matches();
	}
	
	public static boolean matchesIndex(String what)
	{
		Matcher methodMatch=index.matcher(what);
		return methodMatch.matches();
	}
	
	public static boolean matchesEncr(String what)
	{
		Matcher methodMatch=method_enc.matcher(what);
		return methodMatch.matches();
	}
	
	public static boolean matchesDecr(String what)
	{
		Matcher methodMatch=method_dec.matcher(what);
		return methodMatch.matches();
	}
	
	public static boolean isNumeric(String token)
	{
		return token.matches("[0-9]+(\\.[0-9]*)?$");
	}
	
	public static String quote(String param)
	{
		if(!param.startsWith("\"") && !param.endsWith("\""))
			return QUOTE+param+QUOTE;
		return param;
	}
	
	public static String unquote(String param)
	{
		if(param.startsWith("\"") && param.endsWith("\"") && param.length()>1)
			return param.substring(1, param.length()-1);
		return param;
	}
	
	public static boolean isParameter(String word)
	{
		return word.matches("($|\\?).+");
	}
	
	public static List<String> evaluateTextual(String expr)
	{
		String param=expr.trim();
		Pattern pattern=Pattern.compile(LITERAL_REGEX);
		Matcher matcher=pattern.matcher(param);
		ArrayList<String> params=new ArrayList<String>();
		while(matcher.find())
		{
			params.add(unquote(escapeFromJava(matcher.group().trim())));
		}
		return params;
	}

}
